package com.share.order.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.share.common.core.domain.R;
import com.share.common.core.exception.ServiceException;
import com.share.common.security.utils.SecurityUtils;
import com.share.order.api.domain.EndOrderVo;
import com.share.order.api.domain.OrderBill;
import com.share.order.api.domain.OrderInfo;
import com.share.order.api.domain.SubmitOrderVo;
import com.share.order.mapper.OrderBillMapper;
import com.share.order.mapper.OrderInfoMapper;
import com.share.order.service.IOrderInfoService;
import com.share.rules.api.RemoteFeeRuleService;
import com.share.rules.api.domain.FeeRule;
import com.share.rules.api.domain.FeeRuleRequestForm;
import com.share.rules.api.domain.FeeRuleResponseVo;
import com.share.user.api.RemoteUserInfoService;
import com.share.user.api.domain.UserInfo;
import com.share.user.api.domain.UserInfoVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.Minutes;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * 订单Service业务层处理
 *
 * @author atguigu
 * @date 2025-07-18
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements IOrderInfoService {

    private final OrderInfoMapper orderInfoMapper;

    private final RemoteFeeRuleService remoteFeeRuleService;

    private final RemoteUserInfoService remoteUserInfoService;

    private final OrderBillMapper orderBillMapper;

    /**
     * 查询订单列表
     *
     * @param orderInfo 订单
     * @return 订单
     */
    @Override
    public List<OrderInfo> selectOrderInfoList(OrderInfo orderInfo) {
        return orderInfoMapper.selectOrderInfoList(orderInfo);
    }

    /**
     * 获取未完成订单
     */
    @Override
    public OrderInfo getNoFinishOrder(Long userId) {
        // 查询用户是否有使用中与未支付订单
        return this.baseMapper.selectOne(
                new LambdaQueryWrapper<OrderInfo>()
                        .eq(OrderInfo::getUserId, userId)
                        .in(OrderInfo::getStatus, Arrays.asList("0", "1"))// 订单状态：0:充电中 1：未支付 2：已支付
                        .orderByDesc(OrderInfo::getId)
                        .last("limit 1")
        );
    }

    /**
     * 保存订单信息
     * 事务注解确保操作的原子性，发生任何异常都会回滚
     *
     * @param orderForm 提交订单的表单数据对象，包含创建订单所需的基本信息
     * @return 保存成功的订单ID
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long saveOrder(SubmitOrderVo orderForm) {
        // 创建订单信息实体对象
        OrderInfo orderInfo = new OrderInfo();

        // 设置用户ID（关联下单用户）
        orderInfo.setUserId(orderForm.getUserId());

        // 生成8位随机字符串作为订单编号
        orderInfo.setOrderNo(RandomUtil.randomString(8));

        // 设置充电宝编号（关联所租用的充电宝）
        orderInfo.setPowerBankNo(orderForm.getPowerBankNo());

        // 设置订单开始时间（当前时间）
        orderInfo.setStartTime(new Date());

        // 设置起始站点ID和名称（取电地点）
        orderInfo.setStartStationId(orderForm.getStartStationId());
        orderInfo.setStartStationName(orderForm.getStartStationName());

        // 设置起始机柜编号（具体取电机柜）
        orderInfo.setStartCabinetNo(orderForm.getStartCabinetNo());

        // 远程调用费用规则服务，获取对应的计费规则
        // 这里通过Feign或其他远程调用方式获取费用规则详情
        FeeRule feeRule = remoteFeeRuleService.getFeeRule(orderForm.getFeeRuleId()).getData();

        // 设置费用规则ID和描述信息到订单中
        orderInfo.setFeeRuleId(orderForm.getFeeRuleId());
        orderInfo.setFeeRule(feeRule.getDescription());

        // 设置订单状态："0"通常表示初始状态（如待支付、租用中等待定）
        orderInfo.setStatus("0");

        // 设置订单创建时间和创建人
        orderInfo.setCreateTime(new Date());
        orderInfo.setCreateBy(SecurityUtils.getUsername()); // 从安全上下文获取当前登录用户名

        // 远程调用用户信息服务，获取用户昵称
        UserInfo userInfo = remoteUserInfoService.getUserInfo(orderInfo.getUserId()).getData();
        orderInfo.setNickname(userInfo.getNickname());

        // 将订单信息插入到数据库
        this.baseMapper.insert(orderInfo);

        // 返回新创建订单的ID
        return orderInfo.getId();
    }

    /**
     * 结束订单业务处理
     * 根据充电宝归还信息，完成订单结算、费用计算和账单生成
     *
     * @param endOrderVo 订单结束请求对象，包含归还时间、站点等信息
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void endOrder(EndOrderVo endOrderVo) {
        // 1. 查询当前充电宝正在使用的订单
        // 按创建时间降序取第一条，确保处理最新订单
        OrderInfo orderInfo = orderInfoMapper.selectOne(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getPowerBankNo, endOrderVo.getPowerBankNo()).eq(OrderInfo::getStatus, "0") // 订单状态：0=充电中（使用中）
                .orderByDesc(OrderInfo::getCreateTime).last("limit 1"));

        // 如果没有找到使用中的订单，直接返回（可能是初始化插入，无对应订单）
        if (orderInfo == null) {
            log.info("未找到充电宝[{}]的使用中订单，可能为初始化插入", endOrderVo.getPowerBankNo());
            return;
        }

        // 2. 更新订单基本信息
        orderInfo.setEndTime(endOrderVo.getEndTime());                 // 设置结束时间
        orderInfo.setEndStationId(endOrderVo.getEndStationId());       // 设置归还站点ID
        orderInfo.setEndStationName(endOrderVo.getEndStationName());   // 设置归还站点名称
        orderInfo.setEndCabinetNo(endOrderVo.getEndCabinetNo());       // 设置归还柜机编号

        // 计算使用时长（分钟）
        int duration = Minutes.minutesBetween(new DateTime(orderInfo.getStartTime()), new DateTime(orderInfo.getEndTime())).getMinutes();
        orderInfo.setDuration(duration);
        log.info("订单[{}]使用时长: {}分钟", orderInfo.getId(), duration);

        // 3. 调用费用计算服务
        FeeRuleRequestForm feeRuleRequestForm = new FeeRuleRequestForm();
        feeRuleRequestForm.setDuration(duration);                   // 传入使用时长
        feeRuleRequestForm.setFeeRuleId(orderInfo.getFeeRuleId());  // 传入计费规则ID

        // 远程调用费用计算服务
        R<FeeRuleResponseVo> feeRuleResponseVoResult = remoteFeeRuleService.calculateOrderFee(feeRuleRequestForm);

        // 检查费用计算结果
        if (R.FAIL == feeRuleResponseVoResult.getCode()) {
            log.error("费用计算失败: {}", feeRuleResponseVoResult.getMsg());
            throw new ServiceException("订单费用计算失败: " + feeRuleResponseVoResult.getMsg());
        }

        FeeRuleResponseVo feeRuleResponseVo = feeRuleResponseVoResult.getData();
        log.info("订单[{}]费用计算结果: 总金额={}, 免费金额={}, 超出金额={}", orderInfo.getId(), feeRuleResponseVo.getTotalAmount(), feeRuleResponseVo.getFreePrice(), feeRuleResponseVo.getExceedPrice());

        // 4. 更新订单金额和状态
        orderInfo.setTotalAmount(feeRuleResponseVo.getTotalAmount());  // 设置总金额
        orderInfo.setDeductAmount(new BigDecimal(0));                   // 暂不支持抵扣
        orderInfo.setRealAmount(feeRuleResponseVo.getTotalAmount());    // 实付金额

        // 根据金额决定订单状态：0=充电中，1=待支付，2=已支付（0元订单）
        if (orderInfo.getRealAmount().compareTo(BigDecimal.ZERO) == 0) {
            orderInfo.setStatus("2");  // 0元订单直接标记为已支付
        } else {
            orderInfo.setStatus("1");  // 非0元订单标记为待支付
        }

        // 更新订单信息到数据库
        orderInfoMapper.updateById(orderInfo);
        log.info("订单[{}]状态已更新为: {}", orderInfo.getId(), orderInfo.getStatus());

        // 5. 生成免费部分账单
        OrderBill freeOrderBill = new OrderBill();
        freeOrderBill.setOrderId(orderInfo.getId());                // 关联订单ID
        freeOrderBill.setBillItem(feeRuleResponseVo.getFreeDescription()); // 免费描述
        freeOrderBill.setBillAmount(new BigDecimal(0));             // 金额为0
        orderBillMapper.insert(freeOrderBill);
        log.info("订单[{}]免费账单已生成", orderInfo.getId());

        // 6. 生成超出部分账单（如果有）
        if (feeRuleResponseVo.getExceedPrice().doubleValue() > 0) {
            OrderBill exceedOrderBill = new OrderBill();
            exceedOrderBill.setOrderId(orderInfo.getId());                // 关联订单ID
            exceedOrderBill.setBillItem(feeRuleResponseVo.getExceedDescription()); // 超出部分描述
            exceedOrderBill.setBillAmount(feeRuleResponseVo.getExceedPrice()); // 超出金额
            orderBillMapper.insert(exceedOrderBill);
            log.info("订单[{}]超出部分账单已生成，金额: {}", orderInfo.getId(), feeRuleResponseVo.getExceedPrice());
        }
    }

    /**
     * 获取用户订单分页列表
     */
    @Override
    public List<OrderInfo> selectUserOrderInfoList(Long userId) {
        // 查询用户订单列表并按ID降序排列
        List<OrderInfo> orderInfoList = orderInfoMapper.selectList(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getUserId, userId).orderByDesc(OrderInfo::getId));

        if (CollectionUtils.isEmpty(orderInfoList)) {
            return Collections.emptyList();
        }

        // 处理充电中订单的实时计算
        for (OrderInfo order : orderInfoList) {
            // 充电中状态
            if ("0".equals(order.getStatus())) {
                // 计算使用时长（分钟）
                int duration = 0;
                if (order.getStartTime() != null) {
                    DateTime start = new DateTime(order.getStartTime());
                    DateTime now = new DateTime();
                    duration = Math.max(Minutes.minutesBetween(start, now).getMinutes(), 0);
                }
                order.setDuration(duration);

                // 调用远程服务计算费用
                if (duration > 0) {
                    try {
                        FeeRuleRequestForm requestForm = new FeeRuleRequestForm();
                        requestForm.setDuration(duration);
                        requestForm.setFeeRuleId(order.getFeeRuleId());

                        R<FeeRuleResponseVo> result = remoteFeeRuleService.calculateOrderFee(requestForm);

                        if (R.SUCCESS == result.getCode() && result.getData() != null) {
                            FeeRuleResponseVo response = result.getData();
                            order.setTotalAmount(response.getTotalAmount());
                            order.setDeductAmount(BigDecimal.ZERO);
                            order.setRealAmount(response.getTotalAmount());
                        } else {
                            log.error("计算订单费用失败，订单ID: {}, 错误信息: {}", order.getId(), result.getMsg());
                            setDefaultAmounts(order); // 设置默认金额
                        }
                    } catch (Exception e) {
                        log.error("调用费用计算服务异常，订单ID: {}", order.getId(), e);
                        setDefaultAmounts(order); // 设置默认金额
                    }
                } else {
                    setDefaultAmounts(order); // 时长为0时设置默认金额
                }
            }
        }
        return orderInfoList;
    }

    /**
     * 获取订单详细信息
     */
    @Override
    public OrderInfo selectOrderInfoById(Long id) {
        OrderInfo orderInfo = orderInfoMapper.selectById(id);
        if (orderInfo == null) {
            return null;
        }

        // 处理充电中订单的实时计算
        if ("0".equals(orderInfo.getStatus())) {
            int duration = 0;
            if (orderInfo.getStartTime() != null) {
                DateTime start = new DateTime(orderInfo.getStartTime());
                DateTime now = new DateTime();
                duration = Math.max(Minutes.minutesBetween(start, now).getMinutes(), 0);
            }
            orderInfo.setDuration(duration);

            if (duration > 0) {
                try {
                    FeeRuleRequestForm request = new FeeRuleRequestForm();
                    request.setDuration(duration);
                    request.setFeeRuleId(orderInfo.getFeeRuleId());

                    R<FeeRuleResponseVo> result = remoteFeeRuleService.calculateOrderFee(request);

                    if (result != null && R.SUCCESS == result.getCode() && result.getData() != null) {
                        FeeRuleResponseVo response = result.getData();
                        orderInfo.setTotalAmount(response.getTotalAmount());
                        orderInfo.setDeductAmount(BigDecimal.ZERO);
                        orderInfo.setRealAmount(response.getTotalAmount());
                    } else {
                        log.error("计算订单费用失败，订单ID: {}, 错误信息: {}", id, result != null ? result.getMsg() : "未知错误");
                        setDefaultAmounts(orderInfo);
                    }
                } catch (Exception e) {
                    log.error("调用费用计算服务异常，订单ID: {}", id, e);
                    setDefaultAmounts(orderInfo);
                }
            } else {
                setDefaultAmounts(orderInfo);
            }
        }

        // 查询订单账单列表
        List<OrderBill> orderBillList = orderBillMapper.selectList(new LambdaQueryWrapper<OrderBill>().eq(OrderBill::getOrderId, id));
        orderInfo.setOrderBillList(orderBillList);

        // 获取用户信息
        try {
            R<UserInfo> result = remoteUserInfoService.getUserInfo(orderInfo.getUserId());
            if (result != null && R.SUCCESS == result.getCode() && result.getData() != null) {
                UserInfoVo userInfoVo = new UserInfoVo();
                BeanUtils.copyProperties(result.getData(), userInfoVo);
                orderInfo.setUserInfoVo(userInfoVo);
            } else {
                log.error("获取用户信息失败，用户ID: {}, 错误信息: {}", orderInfo.getUserId(), result != null ? result.getMsg() : "未知错误");
                // 可选择设置默认用户信息或保持null
            }
        } catch (Exception e) {
            log.error("调用用户信息服务异常，用户ID: {}", orderInfo.getUserId(), e);
            // 可选择设置默认用户信息或保持null
        }

        return orderInfo;
    }

    /**
     * 根据订单号获取订单信息
     */
    @Override
    public OrderInfo getByOrderNo(String orderNo) {
        return orderInfoMapper.selectOne(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo, orderNo));
    }

    /**
     * 更改订单支付状态
     */
    @Override
    public void processPaySucess(String orderNo) {
        // 获取订单信息
        OrderInfo orderInfo = orderInfoMapper.selectOne(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo, orderNo).select(OrderInfo::getId, OrderInfo::getStatus));
        // 未支付
        if ("1".equals(orderInfo.getStatus())) {
            orderInfo.setStatus("2");
            orderInfo.setPayTime(new Date());
            orderInfoMapper.updateById(orderInfo);
        }
    }

    /**
     * 设置订单默认金额
     */
    private void setDefaultAmounts(OrderInfo order) {
        order.setTotalAmount(BigDecimal.ZERO);
        order.setDeductAmount(BigDecimal.ZERO);
        order.setRealAmount(BigDecimal.ZERO);
    }
}
